<template>
  <el-container>
    <el-aside width="400px" v-if="type==='UML-node'">
      <el-row class="el-row-title">文字设置：</el-row>
      <el-row>内容：</el-row>
      <el-row>
        <el-input
          type="textarea"
          :autosize="{ minRows: 2, maxRows: 4}"
          placeholder="请输入内容"
          v-model="label"
        ></el-input>
      </el-row>
      <el-row>大小:</el-row>
      <el-row>
        <el-input-number
          v-model="fontSize"
          @change="handleFontSize()"
          :min="1"
          :max="30"
          label="描述文字"
        ></el-input-number>
      </el-row>
      <el-row>位置:</el-row>
      <el-row>
        <el-select
          v-model="nodelabelpos"
          placeholder="请选择"
          @change="handleNodeChange($event,'labelpos')"
        >
          <el-option
            v-for="item in nodelabelposes"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          ></el-option>
        </el-select>
      </el-row>
      <el-row>
        偏移:x
        <el-input-number
          v-model="nodelabelrefx"
          @change="handleNodeChange(0,'labelrefx')"
          :min="-100"
          :max="100"
        ></el-input-number>y
        <el-input-number
          v-model="nodelabelrefy"
          @change="handleNodeChange(0,'labelrefy')"
          :min="-100"
          :max="100"
        ></el-input-number>
      </el-row>
      <el-row class="el-row-title">背景填充：</el-row>
      <el-row class="el-row">
        <el-radio v-model="contentType" label="color">纯色填充</el-radio>
        <el-color-picker v-model="fill" show-alpha :predefine="predefineColors"></el-color-picker>
      </el-row>
      <el-row class="el-row">
        <el-radio v-model="contentType" label="image">图片填充</el-radio>
        <el-image style="width: 100px; height: 100px" :src="url" fit="fill"></el-image>
      </el-row>
      <el-row class="el-row-title">边框设置：</el-row>
      <el-row class="el-row">
        线宽：
        <el-input-number
          v-model="lineWidth"
          @change="handleLineWidth()"
          :min="1"
          :max="10"
          label="描述文字"
        ></el-input-number>
      </el-row>
      <el-row>
        颜色：
        <el-color-picker v-model="stroke" show-alpha :predefine="predefineColors"></el-color-picker>
      </el-row>
      <el-row>
        线型：
        <el-input-number
          v-model="fullline"
          @change="handleFulllineChange()"
          :min="0"
          :max="10"
          size="small"
          label="实线长度"
        ></el-input-number>
        <el-input-number
          v-model="dashline"
          @change="handleDashlineChange()"
          :min="0"
          :max="10"
          size="small"
          label="虚线长度"
        ></el-input-number>
      </el-row>
      <el-row class="el-row-title">锚点选择：</el-row>
      <el-row class="el-row">
        顶部
        <el-input-number
          v-model="topAnchorNum"
          @change="handleAnchorChange(arguments,'top')"
          :min="0"
          :max="10"
          label="节点边框宽度"
        ></el-input-number>
      </el-row>
      <el-row class="el-row">
        底部
        <el-input-number
          v-model="bottomAnchorNum"
          @change="handleAnchorChange(arguments,'bottom')"
          :min="0"
          :max="10"
          label="描述文字"
        ></el-input-number>
      </el-row>
      <el-row class="el-row">
        左侧
        <el-input-number
          v-model="leftAnchorNum"
          @change="handleAnchorChange(arguments,'left')"
          :min="0"
          :max="10"
          label="描述文字"
        ></el-input-number>
      </el-row>
      <el-row class="el-row">
        右侧
        <el-input-number
          v-model="rightAnchorNum"
          @change="handleAnchorChange(arguments,'right')"
          :min="0"
          :max="10"
          label="描述文字"
        ></el-input-number>
      </el-row>
    </el-aside>
    <el-aside width="400px" v-else-if="type==='polyline'">
      <el-row class="el-row-title">文字设置：</el-row>
      <el-row>
        内容：
        <el-input
          type="textarea"
          :autosize="{ minRows: 2, maxRows: 4}"
          placeholder="请输入内容"
          v-model="edgelabel"
        ></el-input>
      </el-row>
      <el-row>
        大小:
        <el-input-number
          v-model="edgefontsize"
          @change="handleEdgeChange(0,'edgefontsize')"
          :min="1"
          :max="100"
          label="描述文字"
        ></el-input-number>
      </el-row>
      <el-row>
        位置：
        <el-input-number
          v-model="edgerefX"
          @change="handleEdgeChange(0,'refX')"
          :min="-100"
          :max="100"
          size="mini"
        ></el-input-number>
        <el-input-number
          v-model="edgerefY"
          @change="handleEdgeChange(0,'refY')"
          :min="-100"
          :max="100"
          size="mini"
        ></el-input-number>
      </el-row>
      <el-row class="el-row-title">线型设置：</el-row>
      <el-row class="el-row">
        线宽：
        <el-input-number
          v-model="edgewidth"
          @change="handleEdgeChange(0,'edgewidth')"
          :min="1"
          :max="10"
          label="描述文字"
        ></el-input-number>
      </el-row>
      <el-row>
        颜色：
        <el-color-picker
          @change="handleEdgeChange(0,'edgestroke')"
          v-model="edgestroke"
          show-alpha
          :predefine="predefineColors"
        ></el-color-picker>
      </el-row>
      <el-row>
        线型：
        <el-input-number
          v-model="edgefullline"
          @change="handleEdgeChange(0,'edgefullline')"
          :min="0"
          :max="10"
          size="small"
          label="实线长度1"
        ></el-input-number>
        <el-input-number
          v-model="edgedashline"
          @change="handleEdgeChange(0,'edgedashline')"
          :min="0"
          :max="10"
          size="small"
          label="虚线长度1"
        ></el-input-number>
      </el-row>
      <el-row class="el-row-title">箭头设置：</el-row>
      <el-row>起点箭头</el-row>
      <el-select
        v-model="edgestartarrow"
        placeholder="请选择"
        @change="handleEdgeChange($event,'startarrowtype')"
      >
        <el-option
          v-for="item in edgearrows"
          :key="item.path"
          :label="item.label"
          :value="item.path"
        ></el-option>
      </el-select>
      <el-row>终点箭头</el-row>
      <el-select
        v-model="edgeendarrow"
        placeholder="请选择"
        @change="handleEdgeChange($event,'endarrowtype')"
      >
        <el-option
          v-for="item in edgearrows"
          :key="item.path"
          :label="item.label"
          :value="item.path"
        ></el-option>
      </el-select>
      <el-row class="el-row-title">拐弯处距离节点最小距离：</el-row>
      <el-input-number
        v-model="edgeoffset"
        @change="handleEdgeChange(0,'offset')"
        :min="0"
        :max="100"
        size="small"
      ></el-input-number>
    </el-aside>
    <el-main>
      <div
        id="toolBox"
        style="width:200px; height:600px;border: 2px;border-color: #53534b;border-style: solid; float:left;margin-right:10px"
      ></div>
      <div
        id="mountNode"
        style="width:800px; height:600px;border: 2px;border-color: #53534b;border-style: solid; float:left;"
      ></div>
    </el-main>
  </el-container>
</template>

<script>
import G6 from "@antv/g6";
import { transform, mat3 } from "@antv/matrix-util";
let id = 1000;
export default {
  name: "HelloWorld",

  props: {
    msg: String
  },
  watch: {
    fill: function(val, oldVal) {
      if (!this.selectedItem) {
        return;
      }
      this.selectedItem.getModel().fill = val;
      this.selectedItem.refresh();
    },
    stroke: function(val, oldVal) {
      if (!this.selectedItem) {
        return;
      }
      this.selectedItem.getModel().stroke = val;
      this.selectedItem.refresh();
    },
    contentType: function(val, oldVal) {
      if (!this.selectedItem) {
        return;
      }
      this.selectedItem.getModel().content = val;
      this.selectedItem.refresh();
    },
    label: function(val, oldVal) {
      if (!this.selectedItem) {
        return;
      }
      this.selectedItem.getModel().label = val;
      this.selectedItem.refresh();
    },
    edgelabel: function(val, oldVal) {
      if (!this.selectedItem) {
        return;
      }
      this.selectedItem.getModel().label = val;
      this.selectedItem.refresh();
    }
  },
  data() {
    return {
      graph: null, //G6图
      toolboxgraph: null, //用作工具箱的G6图
      addedNodeCount: 6, //节点数量统计
      edgeIndex: 0,
      goupIndex: 0,
      selectedTooltype: null, //用于确定工具箱中选择的节点样式
      isAddingNode: false, //是否正在增加节点
      data: {
        //节点数据
        nodes: [
          {
            x: 0,
            y: 0,
            id: "node1", // 生成唯一的 id
            myGroupId: "mygroup1",
            size: [50, 50],
            stroke: "#000000",
            fill: "#cdc1e6",
            topAnchors: [],
            rightAnchors: [],
            bottomAnchors: [],
            leftAnchors: [],
            anchorPoints: [
              [0, 0.25],
              [0, 0.5],
              [0, 0.75],
              [1, 0.5]
            ],
            lineDash: [1, 0],
            isDraw: true,
            content: "color",
            imageUrl:
              "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
            lineWidth: 2,
            labelCfg: {
              fontSize: 20,
              fontFamily: "宋体",
              textAlign: "end",
              fill: "#000000",
              labelPos: "inner",
              refX: 0,
              refY: 0
            }
          },
          {
            x: 100,
            y: 100,
            id: "node2", // 生成唯一的 id
            myGroupId: "mygroup1",
            size: [200, 100],
            stroke: "#000000",
            fill: "#cdc1e6",
            topAnchors: [],
            rightAnchors: [],
            bottomAnchors: [],
            leftAnchors: [],
            anchorPoints: [
              [0, 0.25],
              [0, 0.5],
              [0, 0.75],
              [1, 0.5]
            ],
            lineDash: [1, 0],
            isDraw: true,
            content: "color",
            imageUrl:
              "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
            lineWidth: 2,
            labelCfg: {
              fontSize: 20,
              fontFamily: "宋体",
              textAlign: "end",
              fill: "#000000",
              labelPos: "inner",
              refX: 0,
              refY: 0
            }
          },
          {
            id: "mygroup1",
            children: ["node1", "node2"],
            type: "group-node",
            isShow: false
          }
        ],
        //边数据
        edges: []
      },
      toolboxData: {
        nodes: [
          {
            tooltype: "node",
            label: "",
            x: 10,
            y: 20,
            size: [100, 50],
            anchorPoints: [
              [0, 0.25],
              [0, 0.5],
              [0, 0.75],
              [1, 0.5]
            ],
            stroke: "#000000",
            fill: "#cdc1e6",
            isDraw: true,
            content: "color",
            imageUrl: null
          }
          /*           {
            tooltype: "label",
            x: 10,
            y: 100,
            size: [100, 50],
            anchorPoints: [[1, 0.5]],
            stroke: "#000000",
            fill: "#cdc1e6",
            isDraw: false,
            label: "压力等级：string",
            content: "image",
            imageUrl:
              "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"
          } */
        ]
      },
      form: {},
      predefineColors: [
        "#ff4500",
        "#ff8c00",
        "#ffd700",
        "#90ee90",
        "#00ced1",
        "#1e90ff",
        "#c71585",
        "rgba(255, 69, 0, 0.68)",
        "rgb(255, 120, 0)",
        "hsv(51, 100, 98)",
        "hsva(120, 40, 94, 0.5)",
        "hsl(181, 100%, 37%)",
        "hsla(209, 100%, 56%, 0.73)",
        "#c7158577"
      ],
      selectedItem: null,
      seletcedMygroup: null,
      type: "",
      //节点设置
      fill: "rgba(255, 69, 0, 0.68)",
      stroke: "#000000",
      contentType: "",
      url:
        "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
      topAnchorNum: 0,
      bottomAnchorNum: 0,
      leftAnchorNum: 0,
      rightAnchorNum: 0,
      lineWidth: 0,
      fullline: 0,
      dashline: 0,
      label: "",
      fontSize: 0,
      nodelabelpos: "",
      nodelabelposes: [
        {
          value: "top",
          label: "节点上侧"
        },
        {
          value: "right",
          label: "节点右侧"
        },
        {
          value: "bottom",
          label: "节点下侧"
        },
        {
          value: "left",
          label: "节点左侧"
        },
        {
          value: "inner",
          label: "节点内部"
        }
      ],
      nodelabelrefx: 0,
      nodelabelrefy: 0,

      //边属性
      edgestroke: "",
      edgewidth: 0,
      edgelabel: "",
      edgefontsize: 0,
      edgefullline: 0,
      edgedashline: 0,
      edgerefX: 0,
      edgerefY: 0,
      edgestartarrow: null,
      edgeendarrow: null,
      edgearrows: [
        {
          path: "M 0,0 L 15,5 L 15,-5 Z",
          fill: "rgba(0,0,0,1)",
          label: "实心箭头"
        },
        {
          path: "M 15,5 L 0,0 L 15,-5",
          fill: "",
          label: "空心箭头"
        },
        {
          path: "M 0,0 L 15,5 L 30,0 L 15,-5 Z",
          fill: "rgba(0,0,0,1)",
          label: "菱形箭头"
        },
        {
          path: "",
          fill: "",
          label: "没有箭头"
        }
      ],
      edgeoffset: 0
    };
  },
  methods: {
    addNode(type) {
      this.selectedTooltype = type;
      this.isAddingNode = true;
    },
    //根据edge的另外一个锚点的位置，给当前节点的锚点设定位置
    getNewAnchors(model, point) {
      let ths = this;
      const width = model.size[0];
      const height = model.size[1];
      model.anchorPoints.pop();
      const anchors = model.anchorPoints;
      let left = [];
      let right = [];
      let top = [];
      let bottom = [];
      //找出每个锚点所连接的节点ID，并将它们分成上、下、左、右四组。
      for (let i = 0; i < anchors.length; i++) {
        //获取当前锚点所连接的另一个节点的id
        const edge = ths.graph.find("edge", edge => {
          const edgeModel = edge.get("model");
          if (edgeModel.source === model.id && edgeModel.sourceAnchor === i) {
            return true;
          } else if (
            edgeModel.target === model.id &&
            edgeModel.targetAnchor === i
          ) {
            return true;
          } else {
            return false;
          }
        });
        let NodeId = "";

        if (edge.getModel().source === model.id) {
          NodeId = edge.getModel().target;
        } else if (edge.getModel().target === model.id) {
          NodeId = edge.getModel().source;
        }
        let obj = anchors[i];
        if (obj[0] == 0) {
          left.push({ anchor: obj, nodeId: NodeId });
        }
        if (obj[0] == 1) {
          right.push({ anchor: obj, nodeId: NodeId });
        }
        if (obj[1] == 0) {
          top.push({ anchor: obj, nodeId: NodeId });
        }
        if (obj[1] == 1) {
          bottom.push({ anchor: obj, nodeId: NodeId });
        }
      }

      //确定该锚点应该属于哪一条边
      let pos = "";
      if (point.x < model.x) {
        pos = "left";
      } else if (point.x > model.x + width) {
        pos = "right";
      } else if (point.y < model.y) {
        pos = "top";
      } else {
        pos = "bottom";
      }

      let ctpre = 0;
      let lastAnchor = null;
      let tmp = [];
      let newAnchorId = 0;
      let interval = 0.0;
      let nextNode = null;
      switch (pos) {
        case "left":
          ctpre = left.length;
          left.sort((a, b) => {
            return a.anchor[1] - b.anchor[1];
          });
          for (let i = 0; i < ctpre; i++) {
            let node = ths.graph.findById(left[i].nodeId);
            if (i == 0 && ctpre > 1) {
              if (point.y < node.getModel().y) {
                newAnchorId = 0;
              }
              nextNode = ths.graph.findById(left[i + 1].nodeId);
              if (
                point.y >= node.getModel().y &&
                point.y < nextNode.getModel().y
              ) {
                newAnchorId = 1;
              }
            } else if (i == ctpre - 1) {
              if (point.y >= node.getModel().y) {
                newAnchorId = i + 1;
              }
            } else {
              nextNode = ths.graph.findById(left[i + 1].nodeId);
              if (
                point.y >= node.getModel().y &&
                point.y < nextNode.getModel().y
              ) {
                newAnchorId = i + 1;
              }
            }
          }
          interval = 1.0 / (ctpre + 2);
          for (let i = 0; i < ctpre + 1; i++) {
            if (i == newAnchorId) {
              lastAnchor = [0, interval * (i + 1)];
            } else {
              tmp.push({ anchor: [0, interval * (i + 1)] });
            }
          }
          left = tmp;
          break;
        case "right":
          ctpre = right.length;
          right.sort((a, b) => {
            return a.anchor[1] - b.anchor[1];
          });
          for (let i = 0; i < ctpre; i++) {
            let node = ths.graph.findById(right[i].nodeId);
            if (i == 0 && ctpre > 1) {
              if (point.y < node.getModel().y) {
                newAnchorId = 0;
              }
              nextNode = ths.graph.findById(right[i + 1].nodeId);
              if (
                point.y >= node.getModel().y &&
                point.y < nextNode.getModel().y
              ) {
                newAnchorId = 1;
              }
            } else if (i == ctpre - 1) {
              if (point.y >= node.getModel().y) {
                newAnchorId = i + 1;
              }
            } else {
              nextNode = ths.graph.findById(right[i + 1].nodeId);
              if (
                point.y >= node.getModel().y &&
                point.y < nextNode.getModel().y
              ) {
                newAnchorId = i + 1;
              }
            }
          }
          interval = 1.0 / (ctpre + 2);
          for (let i = 0; i < ctpre + 1; i++) {
            if (i == newAnchorId) {
              lastAnchor = [1, interval * (i + 1)];
            } else {
              tmp.push([1, interval * (i + 1)]);
            }
          }
          right = tmp;
          break;
        case "top":
          ctpre = top.length;
          top.sort((a, b) => {
            return a.anchor[1] - b.anchor[1];
          });
          //left = [];
          for (let i = 0; i < ctpre; i++) {
            let node = ths.graph.findById(top[i].nodeId);
            if (i == 0 && ctpre > 1) {
              if (point.x < node.getModel().x) {
                newAnchorId = 0;
              }
              nextNode = ths.graph.findById(top[i + 1].nodeId);
              if (
                point.x >= node.getModel().x &&
                point.x < nextNode.getModel().x
              ) {
                newAnchorId = 1;
              }
            } else if (i == ctpre - 1) {
              if (point.x >= node.getModel().x) {
                newAnchorId = i + 1;
              }
            } else {
              nextNode = ths.graph.findById(right[i + 1].nodeId);
              if (
                point.x >= node.getModel().x &&
                point.x < nextNode.getModel().x
              ) {
                newAnchorId = i + 1;
              }
            }
          }
          interval = 1.0 / (ctpre + 2);
          for (let i = 0; i < ctpre + 1; i++) {
            if (i == newAnchorId) {
              lastAnchor = [interval * (i + 1), 0];
            } else {
              tmp.push([interval * (i + 1), 0]);
            }
          }
          top = tmp;
          break;
        case "bottom":
          ctpre = bottom.length;
          bottom.sort((a, b) => {
            return a.anchor[1] - b.anchor[1];
          });
          //left = [];
          for (let i = 0; i < ctpre; i++) {
            let node = ths.graph.findById(bottom[i].nodeId);
            if (i == 0 && ctpre > 1) {
              if (point.x < node.getModel().x) {
                newAnchorId = 0;
              }
              nextNode = ths.graph.findById(bottom[i + 1].nodeId);
              if (
                point.x >= node.getModel().x &&
                point.x < nextNode.getModel().x
              ) {
                newAnchorId = 1;
              }
            } else if (i == ctpre - 1) {
              if (point.x >= node.getModel().x) {
                newAnchorId = i + 1;
              }
            } else {
              nextNode = ths.graph.findById(right[i + 1].nodeId);
              if (
                point.x >= node.getModel().x &&
                point.x < nextNode.getModel().x
              ) {
                newAnchorId = i + 1;
              }
            }
          }
          interval = 1.0 / (ctpre + 2);
          for (let i = 0; i < ctpre + 1; i++) {
            if (i == newAnchorId) {
              lastAnchor = [interval * (i + 1), 1];
            } else {
              tmp.push([interval * (i + 1), 1]);
            }
          }
          bottom = tmp;
          break;
        default:
          break;
      }

      let newAnchorPoints = [];
      for (const iterator of left) {
        newAnchorPoints.push(iterator.anchor);
      }
      for (const iterator of right) {
        newAnchorPoints.push(iterator.anchor);
      }
      for (const iterator of top) {
        newAnchorPoints.push(iterator.anchor);
      }
      for (const iterator of bottom) {
        newAnchorPoints.push(iterator.anchor);
      }
      newAnchorPoints.push(lastAnchor);

      return newAnchorPoints;
    },
    //刷新某个节点的锚点和连接锚点的边
    refreshAnchor(model, point) {
      //1.先找出所有与当前节点关联的节点
      //2.根据相对位置设定锚点
      //3.
      /* let borderNode = { node: null, sourceEdges: [], targetEdges: [] };
      let borderNodes = [];
      let edges = ths.graph.getEdges();
      let borderEdges = [];
      for (const edge of edges) {
        if (edge.source === model.id) {
          let xx = borderNodes.find(a => {
            a.node === edge.target;
          });
          if (!xx) {
            borderNodes.push({
              node: edge.target,
              sourceEdges: [edge],
              targetEdges: []
            });
          } else {
            xx.sourceEdges.push(edges);
          }
        } else if (edge.target === model.id) {
            
        }
      } */
    },
    handleAnchorChange(arg, pos) {
      if (!this.selectedItem) {
        console.log("selectedItem is null !!!");
        return;
      }
      const model = this.selectedItem.getModel();

      let oldnum = arg[1];
      let curnum = arg[0];
      switch (pos) {
        case "top":
          if (curnum > oldnum) {
            model.topAnchors.push({ edgeId: null, pos: null });
          } else if (curnum < oldnum) {
            for (let i = model.topAnchors.length - 1; i >= 0; i--) {
              if (model.topAnchors[i].edgeId === null) {
                model.topAnchors.splice(i, 1);
                break;
              }
            }
          }
          break;
        case "right":
          if (curnum > oldnum) {
            model.rightAnchors.push({ edgeId: null, pos: null });
          } else if (curnum < oldnum) {
            for (let i = model.rightAnchors.length - 1; i >= 0; i--) {
              if (model.rightAnchors[i].edgeId === null) {
                model.rightAnchors.splice(i, 1);
                break;
              }
            }
          }
          break;
        case "bottom":
          if (curnum > oldnum) {
            model.bottomAnchors.push({ edgeId: null, pos: null });
          } else if (curnum < oldnum) {
            for (let i = model.bottomAnchors.length - 1; i >= 0; i--) {
              if (model.bottomAnchors[i].edgeId === null) {
                model.bottomAnchors.splice(i, 1);
                break;
              }
            }
          }
          break;
        case "left":
          if (curnum > oldnum) {
            model.leftAnchors.push({ edgeId: null, pos: null });
          } else if (curnum < oldnum) {
            for (let i = model.leftAnchors.length - 1; i >= 0; i--) {
              if (model.leftAnchors[i].edgeId === null) {
                model.leftAnchors.splice(i, 1);
                break;
              }
            }
          }
          break;
      }
      this.selectedItem.refresh();
      console.log(model.topAnchors.length);
      for (let i = 0; i < model.topAnchors.length; i++) {
        let anchor = model.topAnchors[i];
        if (anchor.edgeId != null) {
          let edge = this.graph.findById(anchor.edgeId);
          if (anchor.pos === "bg") {
            edge.getModel().sourceAnchor = i;
          } else {
            edge.getModel().targetAnchor = i;
          }
          edge.refresh();
        }
      }
      for (let i = 0; i < model.rightAnchors.length; i++) {
        let anchor = model.rightAnchors[i];
        if (anchor.edgeId != null) {
          console.log(anchor.edgeId);
          let edge = this.graph.findById(anchor.edgeId);
          if (anchor.pos === "bg") {
            edge.getModel().sourceAnchor = i + model.topAnchors.length;
          } else {
            edge.getModel().targetAnchor = i + model.topAnchors.length;
          }
          edge.refresh();
        }
      }
      for (let i = 0; i < model.bottomAnchors.length; i++) {
        let anchor = model.bottomAnchors[i];
        if (anchor.edgeId != null) {
          let edge = this.graph.findById(anchor.edgeId);
          if (anchor.pos === "bg") {
            edge.getModel().sourceAnchor =
              i + model.topAnchors.length + model.rightAnchors.length;
          } else {
            edge.getModel().targetAnchor =
              i + model.topAnchors.length + model.rightAnchors.length;
          }
          edge.refresh();
        }
      }
      for (let i = 0; i < model.leftAnchors.length; i++) {
        let anchor = model.leftAnchors[i];
        if (anchor.edgeId != null) {
          let edge = this.graph.findById(anchor.edgeId);
          if (anchor.pos === "bg") {
            edge.getModel().sourceAnchor =
              i +
              model.topAnchors.length +
              model.rightAnchors.length +
              model.bottomAnchors.length;
          } else {
            edge.getModel().targetAnchor =
              i +
              model.topAnchors.length +
              model.rightAnchors.length +
              model.bottomAnchors.length;
          }
          edge.refresh();
        }
      }
      //for (let i = 0; i < model.rightAnchors.length; i++) {}
      //for (let i = 0; i < model.bottomAnchors.length; i++) {}
      //for (let i = 0; i < model.leftAnchors.length; i++) {}

      //console.log(z);

      /* let newAnchorPoints = [];
      let left = [];
      let right = [];
      let top = [];
      let bottom = [];
      let topInterval = 1.0 / (this.topAnchorNum + 1);
      let bottomInterval = 1.0 / (this.bottomAnchorNum + 1);
      let leftInterval = 1.0 / (this.leftAnchorNum + 1);
      let rightInterval = 1.0 / (this.rightAnchorNum + 1);
      for (let i = 0; i < this.topAnchorNum; i++) {
        top.push([(i + 1) * topInterval, 0]);
      }
      for (let i = 0; i < this.bottomAnchorNum; i++) {
        bottom.push([(i + 1) * bottomInterval, 1]);
      }
      for (let i = 0; i < this.leftAnchorNum; i++) {
        left.push([0, (i + 1) * leftInterval]);
      }
      for (let i = 0; i < this.rightAnchorNum; i++) {
        right.push([1, (i + 1) * rightInterval]);
      }
      for (const iterator of left) {
        newAnchorPoints.push(iterator);
      }
      for (const iterator of right) {
        newAnchorPoints.push(iterator);
      }
      for (const iterator of top) {
        newAnchorPoints.push(iterator);
      }
      for (const iterator of bottom) {
        newAnchorPoints.push(iterator);
      } */

      //this.selectedItem.getModel().anchorPoints = newAnchorPoints;
    },
    handleLineWidth() {
      if (!this.selectedItem) {
        console.log("selectedItem is null !!!");
        return;
      }
      this.selectedItem.getModel().lineWidth = this.lineWidth;
      this.selectedItem.refresh();
    },
    handleFulllineChange() {
      if (!this.selectedItem) {
        console.log("selectedItem is null !!!");
        return;
      }
      this.selectedItem.getModel().lineDash[0] = this.fullline;
      this.selectedItem.refresh();
    },
    handleDashlineChange() {
      if (!this.selectedItem) {
        console.log("selectedItem is null !!!");
        return;
      }
      this.selectedItem.getModel().lineDash[1] = this.dashline;
      this.selectedItem.refresh();
    },
    setSelectedItem(model) {
      let ths = this;
      ths.type = model.type;

      if (model.type === "UML-node") {
        ths.fill = model.fill;
        ths.stroke = model.stroke;
        ths.contentType = model.content;

        /*         const anchors = model.anchorPoints;
        let left = [];
        let right = [];
        let top = [];
        let bottom = [];
        //找出每个锚点所连接的节点ID，并将它们分成上、下、左、右四组。
        for (let i = 0; i < anchors.length; i++) {
          let obj = anchors[i];
          if (obj[0] == 0) {
            left.push(obj);
          }
          if (obj[0] == 1) {
            right.push(obj);
          }
          if (obj[1] == 0) {
            top.push(obj);
          }
          if (obj[1] == 1) {
            bottom.push(obj);
          }
        }
        ths.topAnchorNum = top.length;
        ths.bottomAnchorNum = bottom.length;
        ths.leftAnchorNum = left.length;
        ths.rightAnchorNum = right.length; */

        ths.topAnchorNum = model.topAnchors.length;
        ths.rightAnchorNum = model.rightAnchors.length;
        ths.bottomAnchorNum = model.bottomAnchors.length;
        ths.leftAnchorNum = model.leftAnchors.length;

        ths.lineWidth = model.lineWidth;
        ths.fullline = model.lineDash[0];
        ths.dashline = model.lineDash[1];
        ths.fontSize = model.labelCfg.fontSize;
        ths.label = model.label;
        ths.nodelabelpos = model.labelCfg.labelPos;
        ths.nodelabelrefx = model.labelCfg.refX;
        ths.nodelabelrefy = model.labelCfg.refY;
      } else if (model.type === "polyline") {
        ths.edgestroke = model.style.stroke;
        ths.edgewidth = model.style.lineWidth;
        ths.edgelabel = model.label;
        ths.edgefontsize = model.labelCfg.style.fontSize;

        ths.edgefullline = model.style.lineDash[0];
        ths.edgedashline = model.style.lineDash[1];
        ths.edgerefX = model.labelCfg.refX;
        ths.edgerefY = model.labelCfg.refY;
        ths.edgestartarrow = model.style.startArrow.path;
        ths.edgeendarrow = model.style.endArrow.path;
        ths.edgeoffset = model.style.offset;
      }
    },
    handleFontSize() {
      if (!this.selectedItem) {
        console.log("selectedItem is null !!!");
        return;
      }
      this.selectedItem.getModel().labelCfg.fontSize = this.fontSize;
      this.selectedItem.refresh();
      console.log(this.selectedItem.getModel().labelCfg.fontSize);
    },
    handleNodeChange(event, type) {
      if (!this.selectedItem || this.type != "UML-node") {
        return;
      }
      console.log(type);
      const model = this.selectedItem.getModel();
      switch (type) {
        case "labelpos":
          console.log(this.nodelabelpos);
          model.labelCfg.labelPos = this.nodelabelpos;
          break;
        case "labelrefx":
          model.labelCfg.refX = this.nodelabelrefx;
          break;
        case "labelrefy":
          model.labelCfg.refY = this.nodelabelrefy;
          break;
        default:
          break;
      }
      this.selectedItem.refresh();
    },
    handleEdgeChange(event, type) {
      if (!this.selectedItem || this.type != "polyline") {
        return;
      }
      let obj = {};

      const model = this.selectedItem.getModel();
      switch (type) {
        case "edgewidth":
          model.style.lineWidth = this.edgewidth;
          break;
        case "edgestroke":
          model.style.stroke = this.edgestroke;
          break;
        case "edgefontsize":
          model.labelCfg.style.fontSize = this.edgefontsize;
          break;
        case "edgefullline":
          console.log("1111");
          model.style.lineDash = [1, 1];
          model.style.lineDash[0] = this.edgefullline;
          model.style.lineDash[1] = this.edgedashline;
          console.log(model.style);
          break;
        case "edgedashline":
          console.log("1111");
          model.style.lineDash = [1, 1];
          model.style.lineDash[0] = this.edgefullline;
          model.style.lineDash[1] = this.edgedashline;
          console.log(model.style);
          break;
        case "refX":
          model.labelCfg.refX = this.edgerefX;
          break;
        case "refY":
          model.labelCfg.refY = this.edgerefY;
          break;
        case "endarrowtype":
          if (!model.style.endArrow) {
            model.style.endArrow = {};
          }
          for (const xx of this.edgearrows) {
            if (xx.path === this.edgeendarrow) {
              obj = xx;
            }
          }
          model.style.endArrow.path = obj.path;
          model.style.endArrow.fill = obj.fill;
          break;
        case "startarrowtype":
          if (!model.style.startArrow) {
            model.style.startArrow = {};
          }
          for (const xx of this.edgearrows) {
            if (xx.path === this.edgestartarrow) {
              obj = xx;
            }
          }
          model.style.startArrow.path = obj.path;
          model.style.startArrow.fill = obj.fill;
          break;
        case "offset":
          model.style.offset = this.edgeoffset;
          break;
        default:
          break;
      }
      this.selectedItem.refresh();
    },
    calAnchors(cfg) {
      let newAnchorPoints = [];
      if (!cfg.topAnchors) {
        return;
      }
      let topAnchorNum = cfg.topAnchors.length;
      let rightAnchorNum = cfg.rightAnchors.length;
      let bottomAnchorNum = cfg.bottomAnchors.length;
      let leftAnchorNum = cfg.leftAnchors.length;
      let top = [];
      let right = [];
      let bottom = [];
      let left = [];
      let topInterval = 1.0 / (topAnchorNum + 1);
      let rightInterval = 1.0 / (rightAnchorNum + 1);
      let bottomInterval = 1.0 / (bottomAnchorNum + 1);
      let leftInterval = 1.0 / (leftAnchorNum + 1);
      for (let i = 0; i < topAnchorNum; i++) {
        top.push({
          pos: [(i + 1) * topInterval, 0],
          index: i,
          posIndex: i,
          edgeId: cfg.topAnchors[i].edgeId
        });
      }
      for (let i = 0; i < rightAnchorNum; i++) {
        right.push({
          pos: [1, (i + 1) * rightInterval],
          index: i + topAnchorNum,
          posIndex: i,
          edgeId: cfg.rightAnchors[i].edgeId
        });
      }
      for (let i = 0; i < bottomAnchorNum; i++) {
        bottom.push({
          pos: [(i + 1) * bottomInterval, 1],
          index: i + topAnchorNum + rightAnchorNum,
          posIndex: i,
          edgeId: cfg.bottomAnchors[i].edgeId
        });
      }
      for (let i = 0; i < leftAnchorNum; i++) {
        left.push({
          pos: [0, (i + 1) * leftInterval],
          index: i + topAnchorNum + rightAnchorNum + bottomAnchorNum,
          posIndex: i,
          edgeId: cfg.leftAnchors[i].edgeId
        });
      }

      for (const iterator of top) {
        newAnchorPoints.push(iterator);
      }
      for (const iterator of right) {
        newAnchorPoints.push(iterator);
      }
      for (const iterator of bottom) {
        newAnchorPoints.push(iterator);
      }
      for (const iterator of left) {
        newAnchorPoints.push(iterator);
      }

      return newAnchorPoints;
    },
    CSTestFun() {
      this.graph.fitView();
    }
  },
  mounted() {
    let ths = this;

    //注册自建节点
    G6.registerNode("UML-node", {
      draw(cfg, group) {
        // 如果 cfg 中定义了 style 需要同这里的属性进行融合
        let keyShape = null;
        if (cfg.content == "color") {
          keyShape = group.addShape("rect", {
            attrs: {
              x: 0,
              y: 0,
              //cursor: "pointer",
              width: cfg.size[0] || 100,
              height: cfg.size[1] || 100,
              stroke: cfg.stroke || "#000", // 描边颜色
              fill: cfg.fill || "#cdc1e6", // 填充颜色
              lineWidth: cfg.lineWidth,
              lineDash: cfg.lineDash,
              radius: 4
            },

            // must be assigned in G6 3.3 and later versions. it can be any value you want
            name: "path-shape",
            // 设置 draggable 以允许响应鼠标的图拽事件
            draggable: true
          });
          let matrix = keyShape.getMatrix();
          // 图形或分组的初始矩阵时 null，为了避免变换一个 null 矩阵，需要通过 mat3.create() 将其初始化为单位矩阵
          if (!matrix) matrix = mat3.create();
          // 3*3 矩阵变换，用于二维渲染
          const newMatrix = transform(matrix, [
            ["r", cfg.rotateValue || 0] // rotate
          ]);
          keyShape.setMatrix(newMatrix);
        } else if (cfg.content == "image") {
          keyShape = group.addShape("image", {
            attrs: {
              x: 0,
              y: 0,
              width: cfg.size[0] || 100,
              height: cfg.size[1] || 100,
              img: cfg.imageUrl
            },
            // must be assigned in G6 3.3 and later versions. it can be any value you want
            name: "image-shape"
          });
        }

        let newAnchors = ths.calAnchors(cfg); //计算出锚点坐标
        cfg.anchorPoints = [];

        for (var xx of newAnchors) {
          cfg.anchorPoints.push(xx.pos);
        }

        if (cfg.anchorPoints && cfg.isDraw) {
          for (let i = 0; i < newAnchors.length; i++) {
            let p = newAnchors[i];

            const p_x = p.pos[0];
            const p_y = p.pos[1];
            const p_w = 10;
            const p_h = 10;

            group.addShape("rect", {
              attrs: {
                x: p_x * cfg.size[0] - p_w / 2,
                y: p_y * cfg.size[1] - p_h / 2,
                width: p_w,
                height: p_h,
                fill: "#fffbd2", // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
                cursor: "pointer",
                stroke: "#6b9782"
              },
              // must be assigned in G6 3.3 and later versions. it can be any value you want
              name: "anchorPoint" + i,
              // 设置 draggable 以允许响应鼠标的图拽事件
              draggable: true,
              index: i,
              pos: p.pos,
              posIndex: p.posIndex,
              isLinked: p.edgeId === null ? false : true,
              //isLinked: 'false',
              class: "anchor"
            });
          }
        }

        if (cfg.label) {
          let x = 0;
          let y = 0;
          let textBaseline = "";
          let textAlign = "";
          if (cfg.labelCfg.labelPos == "top") {
            x = 0 + cfg.labelCfg.refX;
            y = 0 + cfg.labelCfg.refY;
            textBaseline = "bottom";
            textAlign = "left";
          } else if (cfg.labelCfg.labelPos == "right") {
            x = cfg.size[0] + 8 + cfg.labelCfg.refX;
            y = cfg.size[1] / 2 + cfg.labelCfg.refY;
            textBaseline = "middle";
            textAlign = "left";
          } else if (cfg.labelCfg.labelPos == "bottom") {
            x = 0 + 8 + cfg.labelCfg.refX;
            y = cfg.size[1] + cfg.labelCfg.refY;
            textBaseline = "top";
            textAlign = "left";
          } else if (cfg.labelCfg.labelPos == "left") {
            x = 0 + cfg.labelCfg.refX;
            y = cfg.size[1] / 2 + cfg.labelCfg.refY;
            textBaseline = "middle";
            textAlign = "right";
          } else if (cfg.labelCfg.labelPos == "inner") {
            x = 0 + 8 + cfg.labelCfg.refX;
            y = cfg.size[1] / 2 + cfg.labelCfg.refY;
            textBaseline = "middle";
            textAlign = "left";
          }
          group.addShape("text", {
            attrs: {
              text: cfg.label,
              x: x,
              y: y,
              fontSize: cfg.labelCfg.fontSize,
              textAlign: textAlign,
              fontFamily: cfg.labelCfg.fontFamily,
              fill: cfg.labelCfg.fill,
              textBaseline: textBaseline
            },
            name: "attr-name",
            draggable: true
          });
        }

        group.addShape("path", {
          attrs: {
            path: this.getPath(cfg.size), // 根据配置获取路径
            stroke: cfg.isShow ? "rgba(0,0,0,1)" : "rgba(0,0,0,0)" // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
            //fill: cfg.color || "#E0EEEE" // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
          },
          name: "path-shape",
          draggable: true
        });

        if (cfg.isShow) {
          let locate = [cfg.x, cfg.y, cfg.size[0], cfg.size[1]];
          this.addZoomPoint(locate, group);
        }

        return keyShape;
      },
      addZoomPoint(locate, group) {
        const x = locate[0];
        const y = locate[1];
        const width = locate[2];
        const height = locate[3];
        const padding = this.padding;
        group.addShape("circle", {
          attrs: {
            x: width / 2,
            y: 0 - padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "top",
          class: "zoomPoint",
          draggable: false
        });
        group.addShape("circle", {
          attrs: {
            x: width + padding,
            y: 0 - padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "rightTop",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: width + padding,
            y: height / 2,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "right",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: width + padding,
            y: height + padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "rightBottom",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: width / 2,
            y: height + padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "bottom",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: 0 - padding,
            y: height + padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "leftBottom",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: 0 - padding,
            y: height / 2,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "left",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: 0 - padding,
            y: 0 - padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "leftTop",
          class: "zoomPoint"
        });
      },

      getPath(size) {
        const padding = this.padding;
        const width = size[0];
        const height = size[1];
        const path = [
          ["M", 0 - padding, 0 - padding], // 左上顶点
          ["L", width + padding, 0 - padding], // 右上顶点
          ["L", width + padding, height + padding], // 右下顶点
          ["L", 0 - padding, height + padding], // 左下顶点
          ["Z"] // 封闭
        ];
        return path;
      },
      padding: 0
    });

    //自定义的用来表示组合的节点
    G6.registerNode("group-node", {
      draw(cfg, group) {
        const locate = this.getLocate(cfg);
        cfg.x = locate[0];
        cfg.y = locate[1];
        const size = [locate[2], locate[3]];
        cfg.size = size;
        const keyShape = group.addShape("path", {
          attrs: {
            path: this.getPath(size), // 根据配置获取路径
            stroke: cfg.isShow ? "rgba(0,0,0,1)" : "rgba(0,0,0,0)" // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
            //fill: cfg.color || "#E0EEEE" // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
          },
          name: "path-shape",
          draggable: true
        });

        if (cfg.isShow) {
          this.addZoomPoint(locate, group);

          return keyShape;
        }
      },

      padding: 5,
      locate: [0, 0, 0, 0],
      getLocate(cfg) {
        const children = cfg.children;
        let left = 0,
          right = 0,
          top = 0,
          bottom = 0;
        for (let i = 0; i < children.length; i++) {
          const obj = children[i];
          const node = ths.graph.findById(obj);
          const model = node.getModel();
          if (i == 0) {
            left = model.x;
            right = model.x + model.size[0];
            top = model.y;
            bottom = model.y + model.size[1];
          } else {
            if (model.x < left) {
              left = model.x;
            }
            if (model.x + model.size[0] > right) {
              right = model.x + model.size[0];
            }
            if (model.y < top) {
              top = model.y;
            }
            if (model.y + model.size[1] > bottom) {
              bottom = model.y + model.size[1];
            }
          }
        }
        this.locate = [left, top, right - left, bottom - top];

        return [left, top, right - left, bottom - top];
      },
      getPath(size) {
        const padding = this.padding;
        const width = size[0];
        const height = size[1];
        const path = [
          ["M", 0 - padding, 0 - padding], // 左上顶点
          ["L", width + padding, 0 - padding], // 右上顶点
          ["L", width + padding, height + padding], // 右下顶点
          ["L", 0 - padding, height + padding], // 左下顶点
          ["Z"] // 封闭
        ];
        return path;
      },

      addZoomPoint(locate, group) {
        const x = locate[0];
        const y = locate[1];
        const width = locate[2];
        const height = locate[3];
        const padding = this.padding;
        group.addShape("circle", {
          attrs: {
            x: width / 2,
            y: 0 - padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "top",
          class: "zoomPoint",
          draggable: false
        });
        group.addShape("circle", {
          attrs: {
            x: width + padding,
            y: 0 - padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "rightTop",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: width + padding,
            y: height / 2,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "right",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: width + padding,
            y: height + padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "rightBottom",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: width / 2,
            y: height + padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "bottom",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: 0 - padding,
            y: height + padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "leftBottom",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: 0 - padding,
            y: height / 2,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "left",
          class: "zoomPoint"
        });
        group.addShape("circle", {
          attrs: {
            x: 0 - padding,
            y: 0 - padding,
            r: 5,
            fill: "rgba(244,244,248,1)",
            stroke: "rgba(165,197,128,1)"
          },
          name: "leftTop",
          class: "zoomPoint"
        });
      }
    });

    //工具箱选择节点样式
    G6.registerBehavior("mousedown-select-node", {
      // 设定该自定义行为需要监听的事件及其响应函数
      getEvents() {
        // 监听的事件为 canvas:click，响应函数是 onClick
        return {
          "node:mousedown": "onMousedown"
        };
      },
      // 点击事件
      onMousedown(ev) {
        const node = ev.item;
        const model = node.getModel();
        ths.selectedTooltype = model.tooltype;
        ths.isAddingNode = true;

        /*         console.log(document.getElementById("mountNode").childNodes[0]);
        console.log(document.getElementById("mountNode").children[0]); */
        //console.log(window.cursor);

        //document.style.cursor = "pointer";
        //canvas.cfg.cursor = 'pointer';
        //console.log(canvas);
        //ths.graph.paint();
        //document.getElementById("toolBox").style.cursor = "cursor:pointer";
      }
    });

    //增加新节点
    G6.registerBehavior("click-add-node", {
      // 设定该自定义行为需要监听的事件及其响应函数
      getEvents() {
        // 监听的事件为 canvas:click，响应函数是 onClick
        return {
          "canvas:mouseup": "onMouseup"
        };
      },
      // 点击事件
      onMouseup(ev) {
        if (!ths.isAddingNode) {
          return;
        }
        const graph = this.graph;
        let model = null;
        // 在图上新增一个节点
        if (ths.selectedTooltype == "label") {
          model = {
            x: graph.getPointByCanvas(ev.canvasX, ev.canvasY).x,
            y: graph.getPointByCanvas(ev.canvasX, ev.canvasY).y,
            id: `node` + ths.addedNodeCount, // 生成唯一的 id
            size: [100, 50],
            stroke: "#000000",
            fill: "#fdcdd2",
            isDraw: true,
            lineDash: [1, 0],
            content: "color",
            imageUrl:
              "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
            lineWidth: 2
          };
          ths.graph.add("node", model);
        } else if (ths.selectedTooltype == "node") {
          model = {
            x: graph.getPointByCanvas(ev.canvasX, ev.canvasY).x,
            y: graph.getPointByCanvas(ev.canvasX, ev.canvasY).y,
            id: `node` + ths.addedNodeCount, // 生成唯一的 id
            size: [200, 100],
            stroke: "#000000",
            fill: "#cdc1e6",
            topAnchors: [],
            rightAnchors: [],
            bottomAnchors: [],
            leftAnchors: [],
            anchorPoints: [
              [0, 0.25],
              [0, 0.5],
              [0, 0.75],
              [1, 0.5]
            ],
            lineDash: [1, 0],
            isDraw: true,
            content: "color",
            imageUrl:
              "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
            lineWidth: 2,
            labelCfg: {
              fontSize: 20,
              fontFamily: "宋体",
              textAlign: "end",
              fill: "#000000",
              labelPos: "inner",
              refX: 0,
              refY: 0
            },
            isShow: true
          };
          ths.graph.add("node", model);
        }
        ths.selectedItem = ths.graph.findById(`node` + ths.addedNodeCount);
        ths.setSelectedItem(model);

        ths.addedNodeCount++;
        ths.isAddingNode = false;
      }
    });

    // 封装点击添加边的交互
    G6.registerBehavior("click-add-edge", {
      // 设定该自定义行为需要监听的事件及其响应函数
      getEvents() {
        return {
          "node:click": "onClick", // 监听事件 node:click，响应函数是 onClick
          mousemove: "onMousemove", // 监听事件 mousemove，响应函数是 onMousemove
          "edge:click": "onEdgeClick" // 监听事件 edge:click，响应函数是 onEdgeClick
        };
      },
      // getEvents 中定义的 'node:click' 的响应函数
      onClick(ev) {
        const node = ev.item;
        const shape = ev.target;
        console.log(node);
        if (
          shape.get("class") === "anchor" &&
          shape.get("isLinked") === false
        ) {
          console.log("can create new edge");
        } else {
          return;
        }
        shape.set("isLinked", true);
        // 鼠标当前点击的节点的位置
        const point = { x: ev.x, y: ev.y };
        const model = node.getModel();
        let pos = "bg";
        if (this.addingEdge && this.edge) {
          //点击目标节点
          pos = "ed";
          ths.graph.updateItem(this.edge, {
            target: model.id,
            targetAnchor: shape.get("index")
          });
          this.edge = null;
          this.addingEdge = false;
        } else {
          ths.edgeIndex++;
          //点击初始节点
          this.edge = ths.graph.addItem("edge", {
            source: model.id,
            target: point,
            sourceAnchor: shape.get("index"),
            style: {
              lineDash: [1, 0],
              stroke: "rgba(0,0,0,1)",
              lineWidth: 2,
              offset: 20,
              endArrow: {
                fill: "",
                path: ""
              },
              startArrow: {
                fill: "",
                path: ""
              },
              lineAppendWidth: 2,
              cursor: "pointer"
            },
            labelCfg: {
              style: {
                fill: "rgba(0,0,0,1)",
                fontSize: 10
              }
            }
          });
          this.addingEdge = true;
        }
        let locate = shape.get("pos");
        let posStr = "0";
        if (locate[0] == 0) {
          posStr = "left";
        } else if (locate[0] == 1) {
          posStr = "right";
        } else if (locate[1] == 0) {
          posStr = "top";
        } else if (locate[1] == 1) {
          posStr = "bottom";
        }
        switch (posStr) {
          case "top":
            node.getModel().topAnchors[shape.get("posIndex")].edgeId =
              "edge" + ths.edgeIndex;
            node.getModel().topAnchors[shape.get("posIndex")].pos = pos;
            break;
          case "right":
            node.getModel().rightAnchors[shape.get("posIndex")].edgeId =
              "edge" + ths.edgeIndex;
            node.getModel().rightAnchors[shape.get("posIndex")].pos = pos;
            break;
          case "bottom":
            node.getModel().bottomAnchors[shape.get("posIndex")].edgeId =
              "edge" + ths.edgeIndex;
            node.getModel().bottomAnchors[shape.get("posIndex")].pos = pos;
            break;
          case "left":
            node.getModel().leftAnchors[shape.get("posIndex")].edgeId =
              "edge" + ths.edgeIndex;
            node.getModel().leftAnchors[shape.get("posIndex")].pos = pos;
            break;
        }
      },
      // getEvents 中定义的 mousemove 的响应函数
      onMousemove(ev) {
        // 鼠标的当前位置
        const point = { x: ev.x, y: ev.y };
        if (this.addingEdge && this.edge) {
          // 更新边的结束点位置为当前鼠标位置
          ths.graph.updateItem(this.edge, {
            target: point
          });
        }
      },
      // getEvents 中定义的 'edge:click' 的响应函数
      onEdgeClick(ev) {
        const currentEdge = ev.item;
        if (this.addingEdge && this.edge == currentEdge) {
          // 点击空白处，删除临时边，并且更新初始节点为未连接状态
          const node = ths.graph.findById(currentEdge.getModel().source);
          const shape = node._cfg.group.cfg.children.find(a => {
            return (
              a.cfg.name == "anchorPoint" + currentEdge.getModel().sourceAnchor
            );
          });
          shape.set("isLinked", false);
          switch (shape.get("pos")) {
            case "top":
              node.getModel().topAnchors[shape.get("posIndex")].edgeId = null;
              break;
            case "right":
              node.getModel().rightAnchors[shape.get("posIndex")].edgeId = null;
              break;
            case "bottom":
              node.getModel().bottomAnchors[
                shape.get("posIndex")
              ].edgeId = null;
              break;
            case "left":
              node.getModel().leftAnchors[shape.get("posIndex")].edgeId = null;
              break;
          }
          ths.graph.removeItem(this.edge);
          this.edge = null;
          this.addingEdge = false;
        }
      }
    });

    // 设置对象显示
    G6.registerBehavior("click-item-setting", {
      // 设定该自定义行为需要监听的事件及其响应函数
      getEvents() {
        return {
          "node:click": "nodeOnClick", // 监听事件 node:click，响应函数是 onClick
          "edge:click": "edgeOnClick", // 监听事件 node:click，响应函数是 onClick
          click: "onClick"
        };
      },
      // getEvents 中定义的 'node:click' 的响应函数
      nodeOnClick(ev) {
        ths.selectedItem = ev.item;
        let model = ths.selectedItem.getModel();
        ths.setSelectedItem(model);

        //先取消选中对象的选中状态度
        if (ths.selectedItem) {
          ths.selectedItem.getModel().isShow = false;
          ths.selectedItem.refresh();
        }
        if (ths.seletcedMygroup) {
          ths.seletcedMygroup.getModel().isShow = false;
          ths.seletcedMygroup.refresh();
        }

        if (model.myGroupId) {
          if (
            ths.seletcedMygroup &&
            ths.seletcedMygroup.getModel().children.indexOf(model.id) != -1
          ) {
            model.isShow = true;
            ths.selectedItem.refresh();
          } else {
            ths.seletcedMygroup = ths.graph.findById(model.myGroupId);
            ths.seletcedMygroup.getModel().isShow = true;
            ths.seletcedMygroup.refresh();
          }
        } else {
          model.isShow = true;
          ths.selectedItem.refresh();
        }
      },
      edgeOnClick(ev) {
        ths.selectedItem = ev.item;
        let model = ths.selectedItem.getModel();
        ths.setSelectedItem(model);
      },
      onClick(ev) {
        if (!ths.selectedItem) {
          return;
        }

        if (!ev.item || (ev.item && ev.item.getModel().type != "UML-node")) {
          console.log("click");

          ths.selectedItem.getModel().isShow = false;
          ths.selectedItem.refresh();
          ths.selectedItem = null;
        }
      }
    });

    G6.registerBehavior("group-operation", {
      tmpNodes: [],
      mousedownlocate: [0, 0], //x,y
      mousedownGroupLocate: [0, 0, 0, 0], //x,y,width,height
      msdwChildrenLocates: [],
      zoomType: "", //'top','rightTop',....'leftTop'
      isMoving: false,
      getEvents() {
        return {
          "node:dragstart": "onDragstart",
          "node:drag": "onDrag",
          "node:dragend": "onDragend",
          "node:mousedown": "onMousedown",
          mousemove: "onMousemove",
          mouseup: "onMouseup",
          click: "onClick"
        };
      },
      onDragstart(ev) {
        //isMoving = true;
        const node = ev.item;
        const shape = ev.target;
        const model = node.getModel();

        switch (model.type) {
          case "UML-node": {
            if (model.myGroupId === null || model.myGroupId === undefined) {
              return;
            }
            const myGroup = ths.graph.findById(model.myGroupId);
            this.tmpNodes = [];
            for (let i = 0; i < myGroup.getModel().children.length; i++) {
              const nodeId = myGroup.getModel().children[i];
              const node = ths.graph.findById(nodeId);
              this.tmpNodes.push([
                node,
                [node.getModel().x, node.getModel().y, node.getModel().size]
              ]);
            }
            this.tmpNodes.push([
              myGroup,
              [myGroup.getModel().x, myGroup.getModel().y, myGroup.getModel().y]
            ]);
            myGroup.isShow = true;
            this.mousedownlocate[0] = ev.x;
            this.mousedownlocate[1] = ev.y;
            break;
          }
          case "group-node": {
            break;
          }
        }
      },
      onDrag(ev) {
        const node = ev.item;
        const shape = ev.target;
        const xOffset = ev.x - this.mousedownlocate[0];
        const yOffset = ev.y - this.mousedownlocate[1];
        const model = node.getModel();
        switch (model.type) {
          case "UML-node":
            for (let i = 0; i < this.tmpNodes.length; i++) {
              let obj = this.tmpNodes[i];
              obj[0].updatePosition({
                x: obj[1][0] + xOffset,
                y: obj[1][1] + yOffset
              });
            }
            break;
          case "group-node": {
            break;
          }
        }
      },
      onDragend(ev) {
        this.tmpNodes = [];
      },
      onMousedown(ev) {
        const node = ev.item;
        const shape = ev.target;
        const model = node.getModel();
        if (model.type != "group-node") {
          return;
        }
        if (shape.get("class") != "zoomPoint") {
          return;
        }
        this.tmpNodes = [];
        this.zoomType = shape.get("name");
        const myGroup = node;
        for (let i = 0; i < myGroup.getModel().children.length; i++) {
          const nodeId = myGroup.getModel().children[i];
          const node = ths.graph.findById(nodeId);
          this.tmpNodes.push([
            node,
            [
              node.getModel().x,
              node.getModel().y,
              node.getModel().size[0],
              node.getModel().size[1]
            ]
          ]);
        }
        this.tmpNodes.push([
          myGroup,
          [myGroup.getModel().x, myGroup.getModel().y, myGroup.getModel().size]
        ]);
        myGroup.isShow = true;

        this.mousedownlocate[0] = ev.x;
        this.mousedownlocate[1] = ev.y;

        this.mousedownGroupLocate[0] = model.x; //x,y,width,height
        this.mousedownGroupLocate[1] = model.y; //x,y,width,height
        this.mousedownGroupLocate[2] = model.size[0]; //x,y,width,height
        this.mousedownGroupLocate[3] = model.size[1]; //x,y,width,height
      },
      onMousemove(ev) {
        if (this.tmpNodes.length === 0) {
          return;
        }
        //const shapeName = shape.get("name");
        const shapeName = "top";
        const preX = this.mousedownGroupLocate[0];
        const preY = this.mousedownGroupLocate[1];
        const preWidth = this.mousedownGroupLocate[2];
        const preHeight = this.mousedownGroupLocate[3];

        switch (this.zoomType) {
          case "top": {
            let y = 0;
            if (ev.y < preY + preHeight) {
              y = ev.y;
            } else {
              y = preY + preHeight;
            }
            const nowHeight = preY + preHeight - y;
            const ratio = (preHeight - y) / (preHeight * 1.0);
            for (let i = 0; i < this.tmpNodes.length - 1; i++) {
              let obj = this.tmpNodes[i];
              const objpreX = obj[1][0];
              const objpreY = obj[1][1];
              const objpreWidth = obj[1][2];
              const objpreHeight = obj[1][3];

              const objpreYRatio = (objpreY - preY) / (preHeight * 1.0);
              const objpreHeightRatio = objpreHeight / (preHeight * 1.0);
              const objY = objpreYRatio * nowHeight + y;
              const objHeight = objpreHeightRatio * nowHeight;
              obj[0].getModel().y = objY;
              obj[0].getModel().size[1] = objHeight;
              obj[0].refresh();
            }
            break;
          }
          case "rightTop": {
            let y = 0;
            if (ev.y < preY + preHeight) {
              y = ev.y;
            } else {
              y = preY + preHeight;
            }
            let x = 0;
            if (ev.x > preX) {
              x = ev.x;
            } else {
              x = preX;
            }
            const nowHeight = preY + preHeight - y;
            const nowWidth = x - preX;
            for (let i = 0; i < this.tmpNodes.length - 1; i++) {
              let obj = this.tmpNodes[i];
              const objpreX = obj[1][0];
              const objpreY = obj[1][1];
              const objpreWidth = obj[1][2];
              const objpreHeight = obj[1][3];

              const objpreYRatio = (objpreY - preY) / (preHeight * 1.0);
              const objpreHeightRatio = objpreHeight / (preHeight * 1.0);
              const objY = objpreYRatio * nowHeight + y;
              const objHeight = objpreHeightRatio * nowHeight;

              const objpreXRatio = (objpreX - preX) / (preWidth * 1.0);
              const objpreWidthRatio = objpreWidth / (preWidth * 1.0);
              const objX = objpreXRatio * nowWidth + preX;
              const objWidth = objpreWidthRatio * nowWidth;

              obj[0].getModel().y = objY;
              obj[0].getModel().x = objX;
              obj[0].getModel().size[0] = objWidth;
              obj[0].getModel().size[1] = objHeight;
              obj[0].refresh();
            }
            break;
          }
          case "right": {
            let x = 0;
            if (ev.x > preX) {
              x = ev.x;
            } else {
              x = preX;
            }
            const nowWidth = x - preX;
            for (let i = 0; i < this.tmpNodes.length - 1; i++) {
              let obj = this.tmpNodes[i];
              const objpreX = obj[1][0];
              const objpreY = obj[1][1];
              const objpreWidth = obj[1][2];
              const objpreHeight = obj[1][3];

              const objpreXRatio = (objpreX - preX) / (preWidth * 1.0);
              const objpreWidthRatio = objpreWidth / (preWidth * 1.0);
              const objX = objpreXRatio * nowWidth + preX;
              const objWidth = objpreWidthRatio * nowWidth;

              obj[0].getModel().x = objX;
              obj[0].getModel().size[0] = objWidth;
              obj[0].refresh();
            }
            break;
          }
          case "rightBottom": {
            let y = 0;
            if (ev.y > preY) {
              y = ev.y;
            } else {
              y = preY;
            }
            let x = 0;
            if (ev.x > preX) {
              x = ev.x;
            } else {
              x = preX;
            }
            const nowHeight = y - preY;
            const nowWidth = x - preX;
            for (let i = 0; i < this.tmpNodes.length - 1; i++) {
              let obj = this.tmpNodes[i];
              const objpreX = obj[1][0];
              const objpreY = obj[1][1];
              const objpreWidth = obj[1][2];
              const objpreHeight = obj[1][3];

              const objpreYRatio = (objpreY - preY) / (preHeight * 1.0);
              const objpreHeightRatio = objpreHeight / (preHeight * 1.0);
              const objY = objpreYRatio * nowHeight + preY;
              const objHeight = objpreHeightRatio * nowHeight;

              const objpreXRatio = (objpreX - preX) / (preWidth * 1.0);
              const objpreWidthRatio = objpreWidth / (preWidth * 1.0);
              const objX = objpreXRatio * nowWidth + preX;
              const objWidth = objpreWidthRatio * nowWidth;

              obj[0].getModel().y = objY;
              obj[0].getModel().x = objX;
              obj[0].getModel().size[0] = objWidth;
              obj[0].getModel().size[1] = objHeight;
              obj[0].refresh();
            }
            break;
          }
          case "bottom": {
            let y = 0;
            if (ev.y > preY) {
              y = ev.y;
            } else {
              y = preY;
            }

            const nowHeight = y - preY;
            for (let i = 0; i < this.tmpNodes.length - 1; i++) {
              let obj = this.tmpNodes[i];
              const objpreX = obj[1][0];
              const objpreY = obj[1][1];
              const objpreWidth = obj[1][2];
              const objpreHeight = obj[1][3];

              const objpreYRatio = (objpreY - preY) / (preHeight * 1.0);
              const objpreHeightRatio = objpreHeight / (preHeight * 1.0);
              const objY = objpreYRatio * nowHeight + preY;
              const objHeight = objpreHeightRatio * nowHeight;

              obj[0].getModel().y = objY;
              obj[0].getModel().size[1] = objHeight;
              obj[0].refresh();
            }
            break;
          }
          case "leftBottom": {
            let y = 0;
            if (ev.y > preY) {
              y = ev.y;
            } else {
              y = preY;
            }
            let x = 0;
            if (ev.x < preX + preWidth) {
              x = ev.x;
            } else {
              x = preX;
            }
            const nowHeight = y - preY;
            const nowWidth = preX + preWidth - x;
            for (let i = 0; i < this.tmpNodes.length - 1; i++) {
              let obj = this.tmpNodes[i];
              const objpreX = obj[1][0];
              const objpreY = obj[1][1];
              const objpreWidth = obj[1][2];
              const objpreHeight = obj[1][3];

              const objpreYRatio = (objpreY - preY) / (preHeight * 1.0);
              const objpreHeightRatio = objpreHeight / (preHeight * 1.0);
              const objY = objpreYRatio * nowHeight + preY;
              const objHeight = objpreHeightRatio * nowHeight;

              const objpreXRatio = (objpreX - preX) / (preWidth * 1.0);
              const objpreWidthRatio = objpreWidth / (preWidth * 1.0);
              const objX = objpreXRatio * nowWidth + x;
              const objWidth = objpreWidthRatio * nowWidth;

              obj[0].getModel().y = objY;
              obj[0].getModel().x = objX;
              obj[0].getModel().size[0] = objWidth;
              obj[0].getModel().size[1] = objHeight;
              obj[0].refresh();
            }
            break;
          }
          case "left": {
            let x = 0;
            if (ev.x < preX + preWidth) {
              x = ev.x;
            } else {
              x = preX;
            }
            const nowWidth = preX + preWidth - x;
            for (let i = 0; i < this.tmpNodes.length - 1; i++) {
              let obj = this.tmpNodes[i];
              const objpreX = obj[1][0];
              const objpreY = obj[1][1];
              const objpreWidth = obj[1][2];
              const objpreHeight = obj[1][3];

              const objpreXRatio = (objpreX - preX) / (preWidth * 1.0);
              const objpreWidthRatio = objpreWidth / (preWidth * 1.0);
              const objX = objpreXRatio * nowWidth + x;
              const objWidth = objpreWidthRatio * nowWidth;

              obj[0].getModel().x = objX;
              obj[0].getModel().size[0] = objWidth;
              obj[0].refresh();
            }
            break;
          }
          case "leftTop": {
            let y = 0;
            if (ev.y < preY + preHeight) {
              y = ev.y;
            } else {
              y = preY;
            }
            let x = 0;
            if (ev.x < preX + preWidth) {
              x = ev.x;
            } else {
              x = preX;
            }
            const nowHeight = preY + preHeight - y;
            const nowWidth = preX + preWidth - x;
            for (let i = 0; i < this.tmpNodes.length - 1; i++) {
              let obj = this.tmpNodes[i];
              const objpreX = obj[1][0];
              const objpreY = obj[1][1];
              const objpreWidth = obj[1][2];
              const objpreHeight = obj[1][3];

              const objpreYRatio = (objpreY - preY) / (preHeight * 1.0);
              const objpreHeightRatio = objpreHeight / (preHeight * 1.0);
              const objY = objpreYRatio * nowHeight + y;
              const objHeight = objpreHeightRatio * nowHeight;

              const objpreXRatio = (objpreX - preX) / (preWidth * 1.0);
              const objpreWidthRatio = objpreWidth / (preWidth * 1.0);
              const objX = objpreXRatio * nowWidth + x;
              const objWidth = objpreWidthRatio * nowWidth;

              obj[0].getModel().y = objY;
              obj[0].getModel().x = objX;
              obj[0].getModel().size[0] = objWidth;
              obj[0].getModel().size[1] = objHeight;
              obj[0].refresh();
            }
            break;
          }
        }
        this.tmpNodes[this.tmpNodes.length - 1][0].refresh();
      },
      onMouseup(ev) {
        this.tmpNodes = [];
      },
      onClick(ev) {
        if (!ths.seletcedMygroup) {
          return;
        }
        if (ev.item == null) {
          ths.seletcedMygroup.getModel().isShow = false;
          ths.seletcedMygroup.refresh();
          ths.seletcedMygroup = null;
        }
        /*         if (ev.item === null || ev.item.type != "UML-node") {
          ths.seletcedMygroup.getModel().isShow = false;
          ths.seletcedMygroup.refresh();
        } */
      }
    });

    //实例化G6画图
    this.graph = new G6.Graph({
      container: "mountNode",
      width: 800,
      height: 600,
      fitView: false,
      fitViewPadding: 20,
      defaultNode: {
        type: "UML-node"
      },
      modes: {
        default: [
          "drag-canvas",
          "zoom-canvas",
          "drag-node",
          "click-add-node",
          "click-add-edge",
          "click-item-setting",
          "group-operation"
        ] // 允许拖拽画布、放缩画布、拖拽节点
        //default: ['click-add-node'],
        //edit: ["click-select"]
      },
      //默认边属性
      defaultEdge: {
        type: "polyline",
        style: {
          lineWidth: 2,
          stroke: "#000000",
          offset: 20,
          lineDash: [1, 0],
          lineAppendWidth: 2,
          cursor: "pointer"
          //endArrow: true
        },
        labelCfg: {
          refY: 0,
          position: "middle",
          style: {
            stroke: "white", // 给文本添加白边和白色背景
            lineWidth: 5, // 文本白边粗细
            fill: "#722ed1" // 文本颜色
          }
        }
      }
    });

    this.toolboxgraph = new G6.Graph({
      container: "toolBox",
      width: 200,
      height: 600,
      fitView: false,
      fitViewPadding: 20,

      defaultNode: {
        type: "UML-node"
      },
      modes: {
        default: ["mousedown-select-node"]
        //default: ["drag-canvas", "zoom-canvas", "drag-node", "click-add-node"] // 允许拖拽画布、放缩画布、拖拽节点
        //default: ['click-add-node'],
        //edit: ["click-select"]
      },
      //默认边属性
      defaultEdge: {
        type: "polyline",
        style: {
          lineWidth: 2,
          stroke: "#000000"
          //endArrow: true
        },
        labelCfg: {
          refY: 0,
          position: "middle",
          style: {
            stroke: "white", // 给文本添加白边和白色背景
            lineWidth: 5, // 文本白边粗细
            fill: "#722ed1" // 文本颜色
          }
        }
      }
    });

    ths.graph.get("canvas").set("localRefresh", false);
    this.graph.data(this.data);
    this.graph.render();
    this.graph.fitView();

    this.toolboxgraph.data(this.toolboxData);
    this.toolboxgraph.render();
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.btn {
  display: inline-block;
  margin: 2px;
  width: 30px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  cursor: pointer;
  border: 1px solid rgba(233, 233, 233, 0);
}
.el-row {
  text-align: left;
}
.el-row-title {
  font-size: large;
  text-align: left;
  margin-top: 20px;
}
</style>
